package com.lfz.demo.controller;

import com.lfz.demo.common.enums.LogType;
import com.lfz.demo.common.enums.MenuType;
import com.lfz.demo.common.target.HoneyLogs;
import com.lfz.demo.entity.User;
import com.lfz.demo.service.RoleService;
import com.lfz.demo.service.UserService;
import com.lfz.demo.utils.RedisUtil;
import com.lfz.demo.vo.DataView;
import com.lfz.demo.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author lfz
 * @date 2025/3/4 16:13
 * @RequestMapping 是 Spring 框架中用于处理 HTTP 请求映射的注解
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    // 缓存时间常量（单位：分钟）
    private static final int CACHE_EXPIRE = 1440; //缓存过期时间（1440分钟）。
    private static final String CACHE_PREFIX = "userMenu:"; //缓存键前缀，避免键冲突。

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 展示所有用户信息（分页）
     */
    @GetMapping("/loadAllUser")
    public DataView loadAllUser(UserVo userVo) {
        // 1、第一种方法
        //if (StringUtils.isNoneBlank(userVo.getUsername())){
        //    userService.loadUserByLeftJoin(userVo.getUsername(),userVo.getPage(),userVo.getLimit());
        //}
        // 1.2、mapper
        //@Select("select a.username,b.name FROM user as a where a.username = #{username} left join ban_ji as b on a.ban_ji_id = b.id limit #{page},#{limit}")

        // 2、第二种方法
        // 查询所有带有模糊查询、等值查询条件 带有分页
//        IPage<User> page = new Page<>(userVo.getPage(), userVo.getLimit());
//        // 创建空的条件构造器
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        // 模糊查询
//        queryWrapper.like(StringUtils.isNoneBlank(userVo.getUsername()), "username", userVo.getUsername());
//        // 等值查询
//        queryWrapper.eq(userVo.getPhone() != null, "phone", userVo.getPhone());
//        // .page(分页, 条件)
//        userService.page(page, queryWrapper);
//
//        return new DataView(page.getTotal(), page.getRecords());

        // 生成缓存键cacheKey
        String cacheKey = CACHE_PREFIX + String.format("loadAllUser, page:%s, limit: %s",
                userVo.getPage(),
                userVo.getLimit()
        );

        try {
            // 尝试从redis缓存获取数据
            DataView cacheData = (DataView) redisUtil.get(cacheKey);
            // 判断是否为空,不为空直接返回缓存数据
            if (cacheData != null){
                return cacheData;
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error("Redis连接失败，降级查询Mysql");
        }

        // 第三种方法 jpa分页
        try {
            // 创建分页对象
            Pageable pageable = PageRequest.of(userVo.getPage() - 1, userVo.getLimit());

            // 创建查询条件
            Specification<User> spec = (root, query, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();

                if (userVo.getUsername() != null && !userVo.getUsername().isEmpty()) {
                    predicates.add(criteriaBuilder.like(root.get("username"), "%" + userVo.getUsername() + "%"));
                }

                if (userVo.getPhone() != null && !userVo.getPhone().isEmpty()) {
                    predicates.add(criteriaBuilder.equal(root.get("phone"), userVo.getPhone()));
                }

                // 查询的用户按照数据表中的id降序排序，使得新注册用户在前面，确保除了超级管理员admin外全部显示
                query.orderBy(criteriaBuilder.desc(root.get("id")));

                // 添加过滤掉用户名是 admin 的条件 criteriaBuilder.notEqual
                predicates.add(criteriaBuilder.notEqual(root.get("username"), "admin"));

                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            };

            // 分页查询
            Page<User> page = userService.findByPage(spec, pageable);

            // 返回数据封装
            DataView dataView = new DataView(page.getTotalElements(), page.getContent());

            // 设置redis缓存
            redisUtil.set(cacheKey, dataView, CACHE_EXPIRE);
            return dataView;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("查询用户管理菜单异常");
            // 可以根据实际情况返回错误信息
            return new DataView(0L, Collections.emptyList());
        }
    }

    /**
     * 新增用户
     */
    @HoneyLogs(operation = "添加用户",type = LogType.ADD,menu = MenuType.User)
    @PostMapping("/addUser")
    public DataView addUser(User user) {
        boolean save = userService.save(user);
        DataView dataView = new DataView();
        if (!save) {
            dataView.setCode(100);
            dataView.setMsg("发送错误，新增用户失败！请联系管理员进行维护！");
        } else {

            dataView.setCode(200);
            dataView.setMsg("新增用户成功！");
            // 添加成功后，默认分配权限为普通用户
            userService.AssignPermissionsByLoadUserIdDescOne();
            // 清理用户管理相关缓存
            clearRelatedCaches();
        }
        return dataView;
    }

    /**
     * 批量删除数据
     * @param ids
     * @return
     */
    @HoneyLogs(operation = "批量删除用户", type = LogType.BATCH_DELETE, menu = MenuType.User)
    @PostMapping("/batchDelete")
    public DataView batchDelete(@RequestBody List<Integer> ids) {
        DataView dataView = new DataView();
        try {
            userService.removeByIds(ids);
            // 清理用户管理相关缓存
            clearRelatedCaches();
            dataView.setCode(200);
            dataView.setMsg("批量删除用户数据成功");
        } catch (Exception e) {
            e.printStackTrace();
            dataView.setCode(500);
            dataView.setMsg("批量删除用户数据失败：" + e.getMessage());
        }
        return dataView;
    }

    /**
     * 修改用户
     */
    @HoneyLogs(operation = "编辑用户信息",type = LogType.UPDATE,menu = MenuType.User)
    @PostMapping("/updateUser")
    public DataView updateUser(User user) {

        boolean save = userService.updateById(user);
        DataView dataView = new DataView();
        if (!save) {
            dataView.setCode(100);
            dataView.setMsg("发送错误，修改用户失败！请联系管理员进行维护！");
        } else {
            // 清理用户管理相关缓存
            clearRelatedCaches();
            dataView.setCode(200);
            dataView.setMsg("修改用户成功！");
        }
        return dataView;
    }

    /**
     * 删除用户
     */
    @HoneyLogs(operation = "删除用户",type = LogType.DELETE,menu = MenuType.User)
    @PostMapping("/deleteUser/{id}")
    public DataView deleteUser(@PathVariable("id") Integer id) {
        String username = getCurrentUsername();
        if (!"admin".equals(username)) {
            return new DataView(403, "用户无权限");
        }

        boolean save = userService.removeById(id);
        DataView dataView = new DataView();
        if (!save) {
            dataView.setCode(100);
            dataView.setMsg("发送错误，删除用户失败！请联系管理员进行维护！");
        } else {
            // 清理用户管理相关缓存
            clearRelatedCaches();
            dataView.setCode(200);
            dataView.setMsg("删除用户成功！");
        }
        return dataView;
    }

    /**
     * 重置密码
     */
    @HoneyLogs(operation = "重置用户密码",type = LogType.UPDATE,menu = MenuType.User)
    @PostMapping("/resetPwd/{id}")
    public DataView resetPwd(@PathVariable("id") Integer id) {
        DataView dataView = new DataView();
        try {
            // 创建用户对象并设置ID和新密码
            User user = new User();
            user.setId(id);
            user.setPassword("123456");

            // 调用服务层方法更新用户密码
            boolean b = userService.updateById(user);

            if (b) {
                // 清理用户管理相关缓存
                clearRelatedCaches();
                // 更新成功，设置响应信息
                dataView.setCode(200);
                dataView.setMsg("重置密码成功！");
            } else {
                // 更新失败，设置响应信息
                dataView.setCode(100);
                dataView.setMsg("发生错误，重置密码失败！请联系管理员进行维护！");
            }
        } catch (Exception e) {
            // 捕获异常，设置响应信息
            dataView.setCode(100);
            dataView.setMsg("发生错误，重置密码失败！请联系管理员进行维护！");
            e.printStackTrace();
        }
        return dataView;
    }

    /**
     * 修改密码
     */
    @HoneyLogs(operation = "修改密码",type = LogType.UPDATE,menu = MenuType.UnFind)
    @PostMapping("/changePassword")
    public DataView changePassword(User user, String newPwdOne, String newPwdTwo) {
        DataView dataView = new DataView();
        Integer id = user.getId();
        // 1、查询数据库旧密码对不对
        User byId = userService.getById(user.getId());
        if (StringUtils.equals(byId.getPassword(),user.getPassword())){
            if(StringUtils.equals(newPwdOne,newPwdTwo)) {
                // 新密码赋值
                user.setPassword(newPwdOne);

                // 调用服务层方法更新用户密码
                boolean b = userService.updateById(user);
                if (b) {
                    // 清理用户管理相关缓存
                    clearRelatedCaches();
                    // 更新成功，设置响应信息
                    dataView.setCode(200);
                    dataView.setMsg("修改密码成功！");
                } else {
                    // 更新失败，设置响应信息
                    dataView.setCode(100);
                    dataView.setMsg("发生错误，修改密码失败！请联系管理员进行维护！");
                }
            } else {
                // 更新失败，设置响应信息
                dataView.setCode(500);
                dataView.setMsg("发生错误，修改密码失败！两次输入密码不一致错误！");
            }
        } else {
            // 更新失败，设置响应信息
            dataView.setCode(500);
            dataView.setMsg("发生错误，修改密码失败！旧密码错误！");
        }
        return dataView;
    }

    /**
     * 点击分配的时候，初始化用户角色
     * 打开分配角色的弹出层
     * 根据 Id 查询用户所拥有的角色
     */
    @GetMapping("/initRoleByUserId")
    public DataView initRoleByUserId(Integer id) {

        String username = getCurrentUsername();
        if (!"admin".equals(username)) {
            return new DataView(403, "用户无权限");
        }

        // 1、查询所有角色
        List<Map<String, Object>> listMaps = roleService.listMaps();
        // 2、查询当前登录用户所拥有的角色
        List<Integer> currentUserRoleIds = roleService.queryUserRoleById(id);
        // 3、让你的前端 变为选中状态
        for (Map<String, Object> map : listMaps) {
            Boolean LAY_CHECKED = false;
            Integer roleId = (Integer) map.get("id");
            for (Integer rid : currentUserRoleIds) {
                if (rid.equals(roleId)) {
                    LAY_CHECKED = true;
                    break;
                }
            }
            map.put("LAY_CHECKED", LAY_CHECKED);
        }
        return new DataView(Long.valueOf(listMaps.size()), listMaps);
    }

    /**
     * 保存用户与角色之间的关系    1:m
     * 先删除再保存关系
     */
    @PostMapping("/saveUserRole")
    public DataView saveUserRole(Integer uid, Integer[] ids) {
        DataView dataView = new DataView();
        userService.saveUserRole(uid, ids);
        dataView.setCode(200);
        dataView.setMsg("用户的角色分配成功！");
        return dataView;
    }

    /**
     * 获取当前操作人信息
     */
    private String getCurrentUsername() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String username = null;
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            Object userObj = request.getSession().getAttribute("user");
            if (userObj instanceof User) {
                User user = (User) userObj;
                username = user.getUsername();
            } else {
                System.out.println("未知用户");
            }
        }
        return username;
    }

    /**
     * 清理相关缓存
     */
    private void clearRelatedCaches(){
        try {
            redisUtil.deletePattern(CACHE_PREFIX + "*");
            logger.info("成功清理用户相关缓存");
        }catch (Exception e){
            e.printStackTrace();
            logger.error("缓存清理失败", e);
        }
    }

}
